#ifndef __NEWSBENCHMARK___HEADER__
#define __NEWSBENCHMARK___HEADER__

#ifdef NEWS_BENCHMARK

#include <string>
#include <sstream>
#include <iostream>
#include <vector>
#include "windows.h"

class NewsBenchmark
{
public:
    typedef __int64             count_type;
    count_type                  m_freq;
    typedef struct _Entry{
        count_type              start;
        count_type              end;
        int                     count; //How many the timer be called.
        int                     sumupOrNot;
        _Entry():start(0),end(0), count(0), sumupOrNot(0){}
    }Entry;

    typedef std::vector<std::string>        record_name;
    typedef std::vector<Entry>              record_entry;
    
    record_name                             m_names;
    record_entry                            m_entries;
    

    //The unique instance
    
private:
    static NewsBenchmark*                          m_instance;
    NewsBenchmark()
    {
        if(!QueryPerformanceFrequency( (LARGE_INTEGER*)&m_freq ) ) 
        {
            m_freq = 0;
        }
    }

public:
    static void Destroy()
    {
        delete m_instance;
    }
    static NewsBenchmark* Instance()
    {
        if( m_instance != NULL)
            return m_instance;
        m_instance = new NewsBenchmark();
        atexit( NewsBenchmark::Destroy );
        return m_instance;
    }

    bool Start( const std::string& name, bool sum = false )
    {
        count_type val;
        if(QueryPerformanceCounter((LARGE_INTEGER*)&val) )
        {
            Entry record;
            record.start = val;
            record.end= 0;
            if( sum )
                record.sumupOrNot = 1;
            else
                record.sumupOrNot = 0;
            //If the name already exist, update it
            record_entry::iterator it2 = m_entries.begin();
            record_name::iterator it = m_names.begin();
            for( ; it != m_names.end(); ++it, ++it2 )
            {
                if( it->compare( name ) == 0)
                {
                    break;
                }
            }
            if( it != m_names.end() )
            {
                //We should sum or just overwrite?
                //When we choose to sum, then we just use current time minor the last time slot
                it2->count ++;
                if( it2->sumupOrNot == 1 )
                {
                    it2->start = val - it2->end + it2->start;
                }else{
                    it2->start = val;
                }
                return true;
            }
            m_names.push_back( name );
            m_entries.push_back( record );
            return true;
        }else{
            return false;
        }
    }
    bool End( const std::string& name )
    {
        count_type val;
        if(QueryPerformanceCounter((LARGE_INTEGER*)&val) )
        {
            record_entry::iterator it2 = m_entries.begin();
            record_name::iterator it = m_names.begin();
            for( ; it != m_names.end(); ++it, ++it2 )
            {
                if( it->compare( name ) == 0)
                {
                    break;
                }
            }
            if( it != m_names.end() )
            {
                //We know the entry should be at the same 
                it2->end = val;
                return true;
            }
            else
            {
                return false;
           }
        }else{
            return false;
        }
    }

    bool Log( std::ostream& log )
    {
        //Log everything to log and then clean the records
        record_name::iterator itName = m_names.begin();
        record_entry::iterator itEntry = m_entries.begin();
        for( ; itName != m_names.end(); ++itName, ++itEntry  )
        {
            __int64 time = ((itEntry->end - itEntry->start)*1000000) / m_freq;
            unsigned int us = (unsigned int)(time & 0xffffffff);
            log << *itName << "(" << itEntry->count << "): " << us << "us  ";
        }
        //Now clear all
        m_names.clear();
        m_entries.clear();
        return true;
    }
};


class NewsBenchmarkClick{
private:
    std::string         m_name;
public:
    NewsBenchmarkClick( const std::string& name, bool sum = false ): m_name(name)
    {
        NewsBenchmark::Instance()->Start( name, sum );
    }

    ~NewsBenchmarkClick()
    {
        NewsBenchmark::Instance()->End(m_name);
    }
};

#ifdef TIMECLICK
#undef TIMECLICK
#endif
#define TIMECLICK( a, b ) NewsBenchmarkClick b( (a) )

#ifdef TIMESUM
#undef TIMESUM
#endif
#define TIMESUM( a, b ) NewsBenchmarkClick b( (a), true )

#ifdef TIMESUMSTART
#undef TIMESUMSTART
#endif
#define TIMESUMSTART( a ) NewsBenchmark::Instance()->Start( (a), true )

#ifdef TIMESUMSTOP
#undef TIMESUMSTOP
#endif
#define TIMESUMSTOP( a ) NewsBenchmark::Instance()->End( (a) )

#ifdef TIMESTART
#undef TIMESTART
#endif
#define TIMESTART( a ) NewsBenchmark::Instance()->Start( (a) )

#ifdef TIMESTOP
#undef TIMESTOP
#endif
#define TIMESTOP( a ) NewsBenchmark::Instance()->End( (a) )

#else
//Undefine the header wrapper, then later ones can
#undef __NEWSBENCHMARK___HEADER__

#ifdef TIMECLICK
#undef TIMECLICK
#endif
#define TIMECLICK( a, b )
 
#ifdef TIMESTART
#undef TIMESTART
#endif
#define TIMESTART( a ) 

#ifdef TIMESTOP
#undef TIMESTOP
#endif
#define TIMESTOP( a ) 

#ifdef TIMESUM
#undef TIMESUM
#endif
#define TIMESUM( a, b )

#ifdef TIMESUMSTART
#undef TIMESUMSTART
#endif
#define TIMESUMSTART( a ) 

#ifdef TIMESUMSTOP
#undef TIMESUMSTOP
#endif
#define TIMESUMSTOP( a ) 

/*
#define TIMECLICK( a )
#define TIMESTART( a )
#define TIMESTOP( a )
*/
#endif

#endif